package com.zx.cloud.security;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLReplaceable;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.baidu.aip.ocr.AipOcr;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import com.zx.cloud.security.model.BaseModel;
import com.zx.cloud.security.model.User;
import com.zx.cloud.security.utils.SingleFactory;

import org.apache.poi.ss.formula.functions.T;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;

import javax.validation.constraints.AssertTrue;

/**
 * @author zhaoxuan
 * @date 2021-02-01 10:08
 **/
public class BaiDuApi {


    public static void main(String[] args) throws JSONException {
        String select="select * from user where username=?";
        String update="update user set username=2 where username=1 ";
        String delete="DELETE from user where username = ? and test =?";
        String insert="insert into user values(1,2,3) ";
        System.out.println("select:\n"+replaceSql(select));
        System.out.println("update:\n"+replaceSql(update));
        System.out.println("delete:\n"+replaceSql(delete));
        System.out.println("insert:\n"+replaceSql(insert));

    }
    public static String replaceSql(String sql){
        List<SQLStatement> mysql = SQLUtils.parseStatements(sql, "");
        SQLTableSource tableSource=null;
        SQLStatement sqlStatement = mysql.get(0);
        if (sqlStatement instanceof SQLUpdateStatement){
            SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement) sqlStatement;
            tableSource = sqlUpdateStatement.getTableSource();
        }else if (sqlStatement instanceof SQLSelectStatement){
            SQLSelectStatement sQLSelectStatement = (SQLSelectStatement) sqlStatement;
            SQLSelect select = sQLSelectStatement.getSelect();
            SQLSelectQueryBlock queryBlock = select.getQueryBlock();
            tableSource = queryBlock.getFrom();
        }else if (sqlStatement instanceof SQLDeleteStatement){
            tableSource = ((SQLDeleteStatement) sqlStatement).getTableSource();
        }else if (sqlStatement instanceof SQLInsertStatement){
            tableSource = ((SQLInsertStatement) sqlStatement).getTableSource();
        }
        if (tableSource==null){
            return sql;
        }
        SQLExprTableSource table = (SQLExprTableSource) tableSource;
        SQLIdentifierExpr expr = (SQLIdentifierExpr)table.getExpr();
        SQLIdentifierExpr target = new SQLIdentifierExpr(expr.getName() + "_1");
        table.setExpr(target);
        return sqlStatement.toString();
    }
    @Test
    public void test(){
       // String s = selectList(User.class);
        User user = new User();
        user.setPassword("123");
        user.setUsername("zx");
        user.setRole("role");
        String deleteSQL = delete(user);

    }
    public String selectList(Class<?> clazz){
        String className = clazz.getSimpleName();
        Method[] methods = clazz.getDeclaredMethods();
        Map<String,Class<?>> fields=new HashMap<>();
        for (int i = methods.length - 1; i >= 0; i--) {
            Method method=methods[i];
            String name = method.getName();
            if (name.contains("get")){
                byte[] bytes = name.substring(3).getBytes();
                bytes=firstToLower(bytes);
                String fileName=new String(bytes);
                fields.put(fileName,method.getReturnType());
            }
        }
        if (fields.size()==0){
            throw new RuntimeException("无法解析到方法get/set");
        }

        SQLSelectQueryBlock sqlSelectQueryBlock = new SQLSelectQueryBlock();
        sqlSelectQueryBlock.setFrom(className,className.toLowerCase());

        SQLSelect sqlSelect = new SQLSelect();
        fields.forEach((k,v)->{
            SQLIdentifierExpr column = new SQLIdentifierExpr(k);
            sqlSelectQueryBlock.getSelectList().add(new SQLSelectItem(column, k));
        });
        sqlSelect.setQuery(sqlSelectQueryBlock);
        SQLSelectStatement sqlSelectStatement=new SQLSelectStatement(sqlSelect);
        String sql = sqlSelectStatement.toString();
        System.out.println(sql);
        return sql;
    }

    public String delete(Object object) {
        String className = object.getClass().getSimpleName();
        Method[] methods = object.getClass().getDeclaredMethods();
        Map<String,Class<?>> fields=new HashMap<>();
        Map<String,Object> fieldValues=new HashMap<>();
        for (int i = methods.length - 1; i >= 0; i--) {
            Method method=methods[i];
            String name = method.getName();
            if (name.startsWith("get")){
                byte[] bytes = name.substring(3).getBytes();
                bytes=firstToLower(bytes);
                String fileName=new String(bytes);
                fields.put(fileName,method.getReturnType());
                Object value = null;
                try {
                    value = method.invoke(object);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                if (value!=null){
                    fieldValues.put(fileName,value);
                }
            }
        }
        if (fields.size()==0){
            throw new RuntimeException("无法解析到方法get/set");
        }
        SQLDeleteStatement sqlDeleteStatement = new SQLDeleteStatement();
        sqlDeleteStatement.setTableSource(new SQLIdentifierExpr(className));

        Set<Map.Entry<String, Object>> entries = fieldValues.entrySet();
        Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
        SQLBinaryOpExpr where= null;
        while (iterator.hasNext()){
            Map.Entry<String, Object> next = iterator.next();
            if (where==null){
                where=new SQLBinaryOpExpr(new SQLIdentifierExpr(next.getKey()),SQLBinaryOperator.Equality,getSQLValuableExpr(next.getValue()));
                sqlDeleteStatement.setWhere(where);
            }else {
                sqlDeleteStatement.addWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr(next.getKey()),SQLBinaryOperator.Equality,getSQLValuableExpr(next.getValue())));
            }
        }
        String sql=sqlDeleteStatement.toLowerCaseString();
        System.out.println(sql);
        return sql;
    }

    public byte[] firstToLower(byte[] bytes){
        if (bytes[0]>='A'&&bytes[0]<='Z'){
            bytes[0]=(byte)(bytes[0]+32);
        }
        return bytes;
    }


    public SQLValuableExpr getSQLValuableExpr(Object value){
        if (value instanceof Integer){
            return new SQLIntegerExpr((Number) value);
        }else if (value instanceof String){
            return new SQLCharExpr((String) value);
        }
        return null;
    }

    @Test
    public void testOptional() throws Exception {
        SingleFactory.Single instance = SingleFactory.getInstance();
/*        Constructor<?> constructor = SingleFactory.Single.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        SingleFactory.Single single = (SingleFactory.Single)constructor.newInstance();*/
        File file = new File("D:\\object");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(instance);
        objectOutputStream.close();
        FileInputStream fileInputStream=new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        SingleFactory.Single single =(SingleFactory.Single) objectInputStream.readObject();
        System.out.println(instance.hashCode());
        System.out.println(single.hashCode());
        System.out.println(instance.equals(single));
    }

}
